package com.sendtion.xrichtext;

import com.sendtion.xrichtext.view.BaseTextField;

import ohos.accessibility.ability.SoftKeyBoardController;
import ohos.accessibility.ability.SoftKeyBoardListener;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Image;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.ScrollView;
import ohos.agp.components.Text;
import ohos.agp.components.TextField;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.KeyEvent;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 编辑富文本
 *
 * @since 2021-06-22
 */
public class RichTextEditor extends ScrollView {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "BaseTextField");
    private static final int INT_500 = 500;
    private static final int INT_10 = 10;
    private static final int INT_16 = 16;
    private static final int INT_8 = 8;
    private static final int INT_50 = 50;
    private static final int INT_15 = 15;
    private static final int EDIT_PADDING = 10;
    private static final float FLOAT_2 = 2.75f;
    private static final float FLOAT_0 = 0.5f;
    private int viewTagIndex = 1;
    private DirectionalLayout allLayout;
    private LayoutScatter inflater;
    private KeyEventListener keyListener;
    private ClickedListener btnListener;
    private FocusChangedListener focusListener;
    private BaseTextField lastFocusEdit;
    private int editNormalPadding = 0; //
    private int disappearingImageIndex = 0;
    private ArrayList<String> imagePaths;
    private String keywords = "";

    private int rtImageHeight = INT_500;
    private int rtImageBottom = INT_10;
    private String rtTextInitHint = "请输入内容";
    private int rtTextSize = INT_16;
    private Color rtTextColor = Color.RED;
    private int rtTextLineSpace = INT_8;

    private OnRtImageDeleteListener onRtImageDeleteListener;
    private OnRtImageClickListener onRtImageClickListener;

    /**
     * RichTextEditor
     *
     * @param context
     * @param attrs
     */
    public RichTextEditor(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    /**
     * RichTextEditor
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public RichTextEditor(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init(context, attrs);
    }

    private void init(Context context, AttrSet attrs) {
        rtImageHeight = attrs.getAttr("rt_editor_image_height").get().getIntegerValue();
        rtImageBottom = attrs.getAttr("rt_editor_image_bottom").get().getIntegerValue();
        rtTextSize = attrs.getAttr("rt_editor_text_size").get().getDimensionValue();
        rtTextLineSpace = attrs.getAttr("rt_editor_text_line_space").get().getDimensionValue();
        rtTextColor = attrs.getAttr("rt_editor_text_color").get().getColorValue();
        rtTextInitHint = attrs.getAttr("rt_editor_text_init_hint").get().getStringValue();

        imagePaths = new ArrayList<>();

        inflater = LayoutScatter.getInstance(context);

        allLayout = new DirectionalLayout(context);
        allLayout.setOrientation(DirectionalLayout.VERTICAL);
        setupLayoutTransitions();
        LayoutConfig layoutParams = new LayoutConfig(LayoutConfig.MATCH_PARENT, LayoutConfig.MATCH_CONTENT);
        allLayout.setPadding(INT_50, INT_15, INT_50, INT_15);
        addComponent(allLayout, layoutParams);

        initListener();

        DirectionalLayout.LayoutConfig firstEditParam = new DirectionalLayout
                .LayoutConfig(ComponentContainer.LayoutConfig.MATCH_PARENT,
                ComponentContainer.LayoutConfig.MATCH_PARENT);
        BaseTextField firstEdit = createEditText(rtTextInitHint, dip2px(context, EDIT_PADDING));
        allLayout.addComponent(firstEdit, firstEditParam);
        lastFocusEdit = firstEdit;
    }

    private void initListener() {
        keyListener = new KeyEventListener() {
            @Override
            public boolean onKeyEvent(Component component, KeyEvent keyEvent) {
                if (keyEvent.isKeyDown() && keyEvent.getKeyCode() == KeyEvent.KEY_DEL) {
                    BaseTextField edit = (BaseTextField) component;
                    onBackspacePress(edit);
                }
                return false;
            }
        };

        btnListener = new ClickedListener() {
            @Override
            public void onClick(Component component) {
                if (component instanceof DataImageView) {
                    DataImageView imageView = (DataImageView) component;
                    if (onRtImageClickListener != null) {
                        onRtImageClickListener.onRtImageClick(imageView, imageView.getAbsolutePath());
                    }
                } else if (component instanceof Image) {
                    DependentLayout parentView = (DependentLayout) component.getComponentParent();
                    onImageCloseClick(parentView);
                }
            }
        };

        focusListener = new FocusChangedListener() {
            @Override
            public void onFocusChange(Component component, boolean b) {
                if (b) {
                    lastFocusEdit = (BaseTextField) component;
                }
            }
        };
    }

    private int dip2px(Context context, float dipValue) {
        float masy = FLOAT_2;
        return (int) (dipValue * masy + FLOAT_0);
    }

    /**
     * 处理软键盘backSpace回退事件
     *
     * @param editTxt 光标所在的文本输入框
     */
    private void onBackspacePress(BaseTextField editTxt) {
        int startSelection = editTxt.getStartPosition();
        if (startSelection == 0) {
            int editIndex = allLayout.getChildIndex(editTxt);
            Component preView = allLayout.getComponentAt(editIndex - 1);
            if (null != preView) {
                if (preView instanceof DependentLayout) {
                    onImageCloseClick(preView);
                } else if (preView instanceof TextField) {
                    String str1 = editTxt.getText().toString();
                    TextField preEdit = (TextField) preView;
                    String str2 = preEdit.getText().toString();
                    editTxt.requestFocus();
                    allLayout.removeComponent(editTxt);
                    showSoftInput();
                    preEdit.setText(String.valueOf(str2 + str1));
                    lastFocusEdit = (BaseTextField) preEdit;
                    lastFocusEdit.requestFocus();
                }
            }
        }
    }

    /**
     * 唤醒软键盘
     *
     * @return boolean
     */
    public static boolean showSoftInput() {
        try {
            Class inputClass = Class.forName("ohos.miscservices.inputmethod.InputMethodController");
            Method method = inputClass.getMethod("getInstance");
            Object object = method.invoke(new Object[]{});
            Method startInput = inputClass.getMethod("startInput", int.class, boolean.class);
            return (boolean) startInput.invoke(object, 1, true);
        } catch (InvocationTargetException e) {
            e.getMessage();
        } catch (NoSuchMethodException e) {
            e.getMessage();
        } catch (IllegalAccessException e) {
            e.getMessage();
        } catch (ClassNotFoundException e) {
            e.getMessage();
        }
        return false;
    }

    /**
     * OnRtImageDeleteListener
     *
     * @since 2021-06-22
     */
    public interface OnRtImageDeleteListener {
        /**
         * onRtImageDelete
         *
         * @param imagePath
         */
        void onRtImageDelete(String imagePath);
    }

    public void setOnRtImageDeleteListener(OnRtImageDeleteListener onRtImageDeleteListener) {
        this.onRtImageDeleteListener = onRtImageDeleteListener;
    }

    /**
     * OnRtImageClickListener
     *
     * @since 2021-06-22
     */
    public interface OnRtImageClickListener {
        /**
         * onRtImageClick
         *
         * @param view
         * @param imagePath
         */
        void onRtImageClick(Component view, String imagePath);
    }

    public void setOnRtImageClickListener(OnRtImageClickListener onRtImageClickListener) {
        this.onRtImageClickListener = onRtImageClickListener;
    }

    /**
     * 处理图片叉掉的点击事件
     *
     * @param view 整个image对应的relativeLayout view
     * @type 删除类型 0代表backspace删除 1代表按红叉按钮删除
     */
    private void onImageCloseClick(Component view) {
        disappearingImageIndex = allLayout.getChildIndex(view);
        List<EditData> dataList = buildEditData();
        EditData editData = dataList.get(disappearingImageIndex);
        if (editData.imagePath != null) {
            if (onRtImageDeleteListener != null) {
                onRtImageDeleteListener.onRtImageDelete(editData.imagePath);
            }
            imagePaths.remove(editData.imagePath);
        }
        allLayout.removeComponent(view);
        mergeEditText();
    }

    /**
     * 清空所有布局
     */
    public void clearAllLayout() {
        allLayout.removeAllComponents();
    }

    /**
     * 获取索引位置
     *
     * @return int
     */
    public int getLastIndex() {
        int childCount = allLayout.getChildCount();
        return childCount;
    }

    /**
     * 生成文本输入框
     *
     * @param hint
     * @param paddingTop
     * @return BaseTextField
     */
    public BaseTextField createEditText(String hint, int paddingTop) {
        Component directionalLayout = inflater.parse(ResourceTable.Layout_rich_edittext, null, false);
        BaseTextField editText = (BaseTextField) directionalLayout.findComponentById(ResourceTable.Id_delet);
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setCornerRadius(0);
        editText.setBubbleElement(shapeElement);
        editText.requestFocus();
        editText.setKeyEventListener(keyListener);
        editText.setTag(viewTagIndex++);
        editText.setPadding(editNormalPadding, paddingTop, editNormalPadding, paddingTop);
        editText.setHint(hint);
        editText.setTextSize(rtTextSize, Text.TextSizeType.PX);
        editText.setTextColor(rtTextColor);
        editText.setLineSpacing(rtTextLineSpace, 1.0f);
        editText.setFocusChangedListener(focusListener);
        return editText;
    }

    /**
     * 生成图片View
     *
     * @return DependentLayout
     */
    private DependentLayout createImageLayout() {
        DependentLayout layout = (DependentLayout) LayoutScatter.getInstance(getContext())
                .parse(ResourceTable.Layout_edit_imageview, null, false);

        layout.setTag(viewTagIndex++);
        Component closeView = layout.findComponentById(ResourceTable.Id_image_close);
        closeView.setTag(layout.getTag());
        closeView.setClickedListener(btnListener);
        DataImageView imageView = (DataImageView) layout.findComponentById(ResourceTable.Id_edit_imageView);
        imageView.setClickedListener(btnListener);
        return layout;
    }

    /**
     * 插入一张图片
     *
     * @param imagePath
     */
    public void insertImage(String imagePath) {
        if (imagePath.isEmpty()) {
            return;
        }
        String lastEditStr = lastFocusEdit.getText();
        int cursorIndex = lastFocusEdit.getStartPosition();
        String editStr1 = lastEditStr.substring(0, cursorIndex).trim();
        String editStr2 = lastEditStr.substring(cursorIndex).trim();
        int lastEditIndex = allLayout.getChildIndex(lastFocusEdit);

        if (lastEditStr.length() == 0) {
            addEditTextAtIndex(lastEditIndex + 1, "");
            addImageViewAtIndex(lastEditIndex + 1, imagePath);
        } else if (editStr1.length() == 0) {
            addImageViewAtIndex(lastEditIndex, imagePath);
            addEditTextAtIndex(lastEditIndex + 1, "");
        } else if (editStr2.length() == 0) {
            addEditTextAtIndex(lastEditIndex + 1, "");
            addImageViewAtIndex(lastEditIndex + 1, imagePath);
        } else {
            lastFocusEdit.setText(editStr1);
            addEditTextAtIndex(lastEditIndex + 1, editStr2);
            addEditTextAtIndex(lastEditIndex + 1, "");
            addImageViewAtIndex(lastEditIndex + 1, imagePath);
        }
        hideKeyBoard();
    }

    /**
     * 隐藏小键盘
     */
    public void hideKeyBoard() {
        new SoftKeyBoardListener() {
            @Override
            public void onSoftKeyBoardShowModeChanged(SoftKeyBoardController softKeyBoardController, int i) {
                softKeyBoardController.setShowMode(0);
            }
        };
    }

    /**
     * 关键字高亮显示
     *
     * @param text
     * @param target
     * @return StringBuilder
     */
    public static StringBuilder highlight(String text, String target) {
        StringBuilder spannable = new StringBuilder(text);
        return spannable;
    }

    public void setKeywords(String keywords) {
        this.keywords = keywords;
    }

    /**
     * 在特定位置插入EditText
     *
     * @param index 位置
     * @param editStr EditText显示的文字
     */
    public void addEditTextAtIndex(final int index, CharSequence editStr) {
        BaseTextField editText2 = createEditText("插入文字", EDIT_PADDING);
        if (!keywords.isEmpty()) {
            StringBuilder textStr = highlight(editStr.toString(), keywords);
            editText2.setText(textStr.toString());
        } else if (!editStr.toString().isEmpty()) {
            editText2.setText(editStr.toString());
        }
        editText2.setFocusChangedListener(focusListener);
        getContext().getUITaskDispatcher().syncDispatch(new Runnable() {
            @Override
            public void run() {
                allLayout.addComponent(editText2, index);
                lastFocusEdit.requestFocus();
            }
        });
        lastFocusEdit = editText2;
    }

    /**
     * 在特定位置添加ImageView
     *
     * @param index
     * @param imagePath
     */
    public void addImageViewAtIndex(final int index, final String imagePath) {
        if (imagePath.isEmpty()) {
            return;
        }
        imagePaths.add(imagePath);
        final DependentLayout imageLayout = createImageLayout();
        DataImageView imageView = (DataImageView) imageLayout.findComponentById(ResourceTable.Id_edit_imageView);
        imageView.setAbsolutePath(imagePath);
        getContext().getUITaskDispatcher().syncDispatch(new Runnable() {
            @Override
            public void run() {
                XRichText.getInstance().loadImage(imagePath, imageView, rtImageHeight);
                allLayout.addComponent(imageLayout, index);
            }
        });
    }

    /**
     * 初始化transition动画
     */
    private void setupLayoutTransitions() {
    }

    /**
     * 图片删除的时候，如果上下方都是EditText，则合并处理
     */
    private void mergeEditText() {
        Component preView = allLayout.getComponentAt(disappearingImageIndex - 1);
        Component nextView = allLayout.getComponentAt(disappearingImageIndex);
        if (preView instanceof TextField && nextView instanceof TextField) {
            TextField preEdit = (TextField) preView;
            TextField nextEdit = (TextField) nextView;
            String str1 = preEdit.getText().toString();
            String str2 = nextEdit.getText().toString();
            String mergeText = "";
            if (str2.length() > 0) {
                mergeText = str1 + System.lineSeparator() + str2;
            } else {
                mergeText = str1;
            }
            allLayout.removeComponent(nextEdit);
            preEdit.setText(mergeText);
            preEdit.requestFocus();
        }
    }

    /**
     * 对外提供的接口, 生成编辑数据上传
     *
     * @return List
     */
    public List<EditData> buildEditData() {
        List<EditData> dataList = new ArrayList<EditData>();
        int num = allLayout.getChildCount();
        for (int index = 0; index < num; index++) {
            Component itemView = allLayout.getComponentAt(index);
            EditData itemData = new EditData();
            if (itemView instanceof TextField) {
                TextField item = (TextField) itemView;
                itemData.inputStr = item.getText().toString();
            } else if (itemView instanceof DependentLayout) {
                DataImageView item = (DataImageView) itemView.findComponentById(ResourceTable.Id_edit_imageView);
                itemData.imagePath = item.getAbsolutePath();
            }
            dataList.add(itemData);
        }
        return dataList;
    }

    /**
     * EditData
     *
     * @since 2021-06-22
     */
    public static class EditData {
        /**
         * inputStr
         */
        public String inputStr;
        /**
         * imagePath
         */
        public String imagePath;
        /**
         * bitmap
         */
        public PixelMap bitmap;
    }

    public int getRtImageHeight() {
        return rtImageHeight;
    }

    public void setRtImageHeight(int rtImageHeight) {
        this.rtImageHeight = rtImageHeight;
    }

    public int getRtImageBottom() {
        return rtImageBottom;
    }

    public void setRtImageBottom(int rtImageBottom) {
        this.rtImageBottom = rtImageBottom;
    }

    public String getRtTextInitHint() {
        return rtTextInitHint;
    }

    public void setRtTextInitHint(String rtTextInitHint) {
        this.rtTextInitHint = rtTextInitHint;
    }

    public int getRtTextSize() {
        return rtTextSize;
    }

    public void setRtTextSize(int rtTextSize) {
        this.rtTextSize = rtTextSize;
    }

    public Color getRtTextColor() {
        return rtTextColor;
    }

    public void setRtTextColor(Color rtTextColor) {
        this.rtTextColor = rtTextColor;
    }

    public int getRtTextLineSpace() {
        return rtTextLineSpace;
    }

    public void setRtTextLineSpace(int rtTextLineSpace) {
        this.rtTextLineSpace = rtTextLineSpace;
    }
}
